#include "chatservice.hpp"
#include "public.hpp"


#include <muduo/base/Logging.h>
using namespace muduo;
#include <iostream>
#include <vector>
#include <map>
using namespace std;
#include "chatservice.hpp"

// 注册消息以及handler回调函数
ChatService::ChatService()
{
    _msgHandlerMap.insert({LOGIN_MSG, std::bind(&ChatService::login, this, _1, _2, _3)});
    _msgHandlerMap.insert({REG_MSG, std::bind(&ChatService::reg, this, _1, _2, _3)});
    _msgHandlerMap.insert({ONE_CHAT_MSG, std::bind(&ChatService::oneChat, this, _1, _2, _3)});
    _msgHandlerMap.insert({ADD_FRIEND_MSG, std::bind(&ChatService::addFriend, this, _1, _2, _3)});
    _msgHandlerMap.insert({CREATE_GROUP_MSG, std::bind(&ChatService::createGroup, this, _1, _2, _3)});
    _msgHandlerMap.insert({ADD_GROUP_MSG, std::bind(&ChatService::addGroup, this, _1, _2, _3)});
    _msgHandlerMap.insert({GROUP_CHAT_MSG, std::bind(&ChatService::groupChat, this, _1, _2, _3)});
    _msgHandlerMap.insert({LOGINOUT_MSG, std::bind(&ChatService::loginout, this, _1, _2, _3)});
    _msgHandlerMap.insert({CHAT_AI_MSG,std::bind(&ChatService::chatAI,this,_1,_2,_3)});

    if(_redis.connect())
    {
        _redis.init_notify_handler(std::bind(&ChatService::handleRedisSubscribeMessage,this,_1,_2));
    }
}

// 获取单利对象的接口
ChatService *ChatService::instance()
{
    static ChatService service;
    return &service;
}

// 处理登录业务
void ChatService::login(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    
    int id = js["id"];
    

    string pwd = js["password"];

    User user = _userModel.query(id);
    if (user.getId() == id && user.getPwd() == pwd) // 验证账户密码是否正确
    {
        // 已经登录，不允许重复登录
        if (user.getState() == "online")
        {
            json response;
            response["msgid"] = LOGIN_MSG_ACK;
            response["errno"] = 2; // 重复登录
            response["errmsg"] = "不允许重复登录";
            conn->send(response.dump());
        }
        else // 成功登录
        {
            // 记录用户连接信息
            {
                lock_guard<mutex> lock(_connMutex);
                _userConnMap.insert({id, conn});
            }

            // 登录成功向redis注册channel（id）
            _redis.subscribe(id);

            // 登录成功,更新用户状态信息 offline=>online
            user.setState("online");
            _userModel.updateState(user);

            json response;
            response["msgid"] = LOGIN_MSG_ACK;
            response["errno"] = 0; // 响应成功
            response["id"] = user.getId();
            response["name"] = user.getName();

            // 查询该用户是否有离线消息
            vector<string> vec = _offlineMsgModel.query(id);
            if (!vec.empty())
            {
                // 直接传入容器，让客户端处理
                response["offlinemsg"] = vec;
                _offlineMsgModel.remove(id);
            }

            // 查询该用户的好友信息并返回
            vector<User> userVec = _friendModel.query(id);
            if (!userVec.empty())
            {
                vector<string> vec2;
                for (User &user : userVec)
                {
                    // 将用户信息转化为json再传入vector<string>中
                    // 再传入 response
                    json js;
                    js["id"] = user.getId();
                    js["name"] = user.getName();
                    js["state"] = user.getState();
                    vec2.push_back(js.dump());
                }
                response["friends"] = vec2;
            }

            // 查询用户的群组消息
            vector<Group> userGroup = _groupModel.queryGroups(id);
            if (!userGroup.empty())
            {
                vector<string> groupV;
                for (Group &group : userGroup)
                {
                    json gr;
                    gr["id"] = group.getId();
                    gr["groupname"] = group.getName();
                    gr["groupdesc"] = group.getDesc();
                    vector<string> userV;
                    for (GroupUser &user : group.getUsers())
                    {
                        json js;
                        js["id"] = user.getId();
                        js["name"] = user.getName();
                        js["state"] = user.getState();
                        js["role"] = user.getRole();
                        userV.push_back(js.dump());
                    }
                    gr["users"] = userV;
                    groupV.push_back(gr.dump());
                }
                response["groups"] = groupV;
            }
            conn->send(response.dump());
        }
    }
    else
    {
        // 该用户不存在，或者密码错误 登录失败
        json response;
        response["msgid"] = LOGIN_MSG_ACK;
        response["errno"] = 1; // 响应失败
        response["errmsg"] = "用户名或者密码错误";
        conn->send(response.dump());
    }
}

// 处理注册业务 json[name] json[password]
void ChatService::reg(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    // LOG_INFO<<"do reg service";
    string name = js["name"];
    string pwd = js["password"];
    // LOG_INFO<<"name: "<<name<<"password: "<<pwd;
    User user;
    user.setName(name);
    user.setPwd(pwd);
    bool state = _userModel.insert(user);

    if (state)
    {
        // 注册成功
        json response;
        response["msgid"] = REG_MSG_ACK;
        response["errno"] = 0; // 响应成功
        response["id"] = user.getId();
        conn->send(response.dump());
    }
    else
    {
        // 注册失败
        json response;
        response["msgid"] = REG_MSG_ACK;
        response["errno"] = 1; // 响应失败
        conn->send(response.dump());
    }
}

// 一对一聊天业务
void ChatService::oneChat(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    int toid = js["to"];

    // 查看用户是否在当前server登录
    {
        lock_guard<mutex> lock(_connMutex);
        auto it = _userConnMap.find(toid);
        if (it != _userConnMap.end())
        {
            // 在线，转发消息 服务器主动推动消息给toid用户
            it->second->send(js.dump());
            return;
        }
    }

    // 那也可能在其余server中，所有查询 toid 的存在状态
    User user = _userModel.query(toid);
    if(user.getState() == "online")
    {
        _redis.publish(toid,js.dump());
        return ;
    } 


    // 不在线的话存储离线消息
    _offlineMsgModel.insert(toid, js.dump());
}

// 添加好友业务 msgid id friendid
void ChatService::addFriend(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    int userid = js["id"];
    int friendid = js["friendid"];

    // 存储好友信息
    _friendModel.insert(userid, friendid);
}

// 创建群聊
void ChatService::createGroup(const TcpConnectionPtr &conn, json &js, Timestamp time)
{

    int userid = js["id"];
    string name = js["name"];
    string desc = js["desc"];

    Group group(-1, name, desc);
    if (_groupModel.createGroup(group))
    {
        _groupModel.addGroup(userid, group.getId(), "creator");
    }
}

// 加入群组
void ChatService::addGroup(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    int userid = js["id"];
    int groupid = js["groupid"];
    _groupModel.addGroup(userid, groupid, "normal");
}

// 群组聊天
void ChatService::groupChat(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    int userid = js["id"];
    int groupid = js["groupid"];
    vector<int> groupUsers = _groupModel.queryGroupUsers(userid, groupid);

    
    lock_guard<mutex> lock(_connMutex);
    for (int id : groupUsers)
    {
        auto p = _userConnMap.find(id);
        if (p != _userConnMap.end())  // 如果群员在当前server直接发消息
        {
            p->second->send(js.dump());
        }
        else  // 如果不在当前server
        {
            User user = _userModel.query(id);
            if(user.getState() == "online") // 在其余server
            {
                _redis.publish(id,js.dump());
            }
            else
                _offlineMsgModel.insert(id, js.dump());
        }
    }
}

// 注销
void ChatService::loginout(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    int id = js["id"];
    {
        lock_guard<mutex> lock(_connMutex);
        auto it = _userConnMap.find(id);
        if (it != _userConnMap.end())
        {
            _userConnMap.erase(id);
        }
    }

    {
        lock_guard<mutex> lock(_aiMutex);
        auto it = _aiMsg.find(id);
        if (it != _aiMsg.end())
        {
            _aiMsg.erase(id);
        }
    }

    _redis.unsubscribe(id);

    User user(id, "", "", "offline");
    _userModel.updateState(user);
}

// AI聊天
void ChatService::chatAI(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    int id = js["id"];
    string msg = js["msg"];
    json historyMsg;

    {
        lock_guard<mutex> lock(_aiMutex);
        _aiMsg[id].push_back({{"content",msg},{"role","user"}});
        historyMsg["data"] =  _aiMsg[id];
    }

    string res = _aiModel.chat(historyMsg);

    {
        lock_guard<mutex> lock(_aiMutex);
        _aiMsg[id].push_back({{"content",res},{"role","assistant"}});
    }

    json response;
    response["msgid"] = CHAT_AI_ACK;
    response["msg"] = res;
    conn->send(response.dump());
}

// redis处理业务
void ChatService::handleRedisSubscribeMessage(int userid, string msg)
{

    lock_guard<mutex> lock(_connMutex);

    auto it = _userConnMap.find(userid);
    if(it != _userConnMap.end())
    {
        it->second->send(msg);
        return;
    }
    
    _offlineMsgModel.insert(userid,msg);
}

// 获取消息对应的处理器
MsgHandler ChatService::getHandler(int msgid)
{
    // 记录错误日志，msgin没有对应的事件回调
    auto it = _msgHandlerMap.find(msgid);
    if (it == _msgHandlerMap.end())
    {

        // 返回默认处理器，空操作
        return [=](const TcpConnectionPtr &conn,
                   json &js, Timestamp)
        {
            LOG_ERROR << "msgid: " << msgid << " can not find handler!";
        };
    }
    else
    {
        return _msgHandlerMap[msgid];
    }
}

// 用户关闭的消息
void ChatService::clientCloseException(const TcpConnectionPtr &conn)
{
    User user;

    {
        lock_guard<mutex> lock(_connMutex);

        for (auto it = _userConnMap.begin(); it != _userConnMap.end(); ++it)
        {
            if (it->second == conn)
            {
                // 从map中删除用户的 连接信息
                user.setId(it->first);
                _userConnMap.erase(it);
                break;
            }
        }
    }


    _redis.unsubscribe(user.getId());

    if (user.getId() != -1)
    {
        user.setState("offline");
        _userModel.updateState(user);
    }

    {
        lock_guard<mutex> lock(_aiMutex);
        auto it = _aiMsg.find(user.getId());
        if (it != _aiMsg.end())
        {
            _aiMsg.erase(user.getId());
        }
    }
}

void ChatService::reset()
{
    // 把所有online用户 设置为offline
    _userModel.resetState();
}
